package com.cjj.springsecurity.security;

import cn.hutool.core.collection.CollectionUtil;
import com.cjj.common.dao.master.ICPermissionService;
import com.cjj.common.entity.dto.security.MenuRole;
import com.cjj.common.entity.po.master.CRole;
import com.cjj.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;

import javax.annotation.PostConstruct;
import java.util.Collection;
import java.util.List;

/**
 * @author by BrownC_
 * @date 2021/12/21 14:13:00
 * @email ccc-ju@outlook.com
 */
@Component
@Slf4j
public class CustomerFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    private static final String ROLE_NEED_LOGIN = "ROLE_NEED_LOGIN";

    @Autowired
    private ICPermissionService permissionService;

    /**
     * 从数据库加载所有的permission资源信息
     */
    private static List<MenuRole> allPermission = null;

    /**
     * 获取所有的资源信息
     * 在getAttributes()方法内不可直接使用menuMapper，因为Security先于Spring加载，此时还没有注入，会报空指针异常
     * 被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行，并且只会被服务器执行一次,依赖注入初始化后会自动执行该方法
     * @return 数据库中所有的路径url
     */
    @PostConstruct
    private List<MenuRole> getAllPermission(){
        if(CollectionUtil.isEmpty(allPermission)){
            allPermission = permissionService.getAllMenus();
        }
        return allPermission;
    }

    /**
     * 通过当前请求的URL获取角色信息
     *
     * @param o(FilterInvocation) 用于获取当前请求的url
     * @return 当前请求url所需的角色
     */
    @Override
    public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException {
        AntPathMatcher antPathMatcher = new AntPathMatcher();
        String requestUrl = ((FilterInvocation) o).getRequestUrl();
        log.info("当前请求的url------>" + requestUrl);
        for(MenuRole permission : allPermission){
            if(antPathMatcher.match(permission.getUrl(), requestUrl)){
                List<CRole> roles = permission.getRoles();
                String[] rolesName = roles.stream().filter(role -> !StringUtils.isEmpty(role.getRoleNameEn())).map(CRole::getRoleNameEn).toArray(String[]::new);
                return SecurityConfig.createList(rolesName);
            }
        }
        return SecurityConfig.createList(ROLE_NEED_LOGIN);
    }

    /**
     * 定义好所有的权限资源
     * Spring Security在启动时会校验相关配置是否正确，如果不需要校验，直接返回null
     * @return 配置集合
     */
    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    /**
     * 是否支持校验
     * @param aClass 校验参数
     * @return true | false
     */
    @Override
    public boolean supports(Class<?> aClass) {
        return true;
    }
}
